package com.mhc.suzuki.controller;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.mhc.haval.security.model.User;
import com.mhc.suzuki.constant.AnnexConstant;
import com.mhc.suzuki.constant.AnnexGroupEnum;
import com.mhc.suzuki.constant.ErrorCodeEnum;
import com.mhc.suzuki.constant.OssConfig;
import com.mhc.suzuki.dal.model.AnnexListDO;
import com.mhc.suzuki.form.AnnexForm;
import com.mhc.suzuki.service.AnnexListService;
import com.mhc.suzuki.util.BeanCopierUtil;
import com.mhc.suzuki.util.UniqueIdGen;
import com.mhc.suzuki.vo.AnnexListVO;
import com.subaru.common.entity.BizResult;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URL;
import java.sql.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 附件📎上传管理
 * Created by kanon on 17/8/11 19:18.
 */
@Slf4j
@RestController
@RequestMapping(value = "/annex")
public class AnnexController {

    @Autowired
    private AnnexListService annexListService;
    @Autowired
    private OssConfig ossConfig;

    @ApiOperation(value = "检验OSS 签名", notes = "")
    @RequestMapping(value = {"/check/{annexGroup}"}, method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "annexGroup", value = "附件分组", paramType = "path", required = true, dataType = "String"),
    })
    public void check(@PathVariable String annexGroup, HttpServletResponse response, HttpServletRequest request) {
        String endpoint = ossConfig.getEndpoint();
        String accessId = ossConfig.getAccessId();
        String accessKey = ossConfig.getAccessKey();
        String bucket = ossConfig.getBucket();
        //根据页面传递group类型，选择对应的目录
        String dir = AnnexGroupEnum.getAnnexGroupEnum(Integer.parseInt(annexGroup)).getName() + "/";
        String host = "http://" + bucket + "." + endpoint;
        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        try {
            long expireTime = ossConfig.getUploadExpireTime();
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = client.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = client.calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<>(64);
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            JSONObject ja1 = JSONObject.fromObject(respMap);
            log.debug(ja1.toString());
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST");
            response(request, response, ja1.toString());

        } catch (Exception e) {
            log.error("error in check", e);
        } finally {
            // 关闭client
            client.shutdown();
        }
    }

    private void response(HttpServletRequest request, HttpServletResponse response, String results) throws IOException {
        String callbackFunName = request.getParameter("callback");
        if (StringUtils.isBlank(callbackFunName)) {
            response.getWriter().println(results);
        } else {
            response.getWriter().println(callbackFunName + "( " + results + " )");
            response.setStatus(HttpServletResponse.SC_OK);
            response.flushBuffer(
            );
        }
    }

    @ApiOperation(value = "获取加 token后的OSS资源地址", notes = "")
    @RequestMapping(value = {"/url/{annexGroup}"}, method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "annexGroup", value = "附件分组", paramType = "path", required = true, dataType = "String"),
            @ApiImplicitParam(name = "name", value = "附件名称", paramType = "query", required = true, dataType = "String"),
    })
    public void getUrl(@PathVariable String annexGroup, @RequestParam String name, HttpServletResponse response, HttpServletRequest request) {
        String endpoint = ossConfig.getEndpoint();
        String accessId = ossConfig.getAccessId();
        String accessKey = ossConfig.getAccessKey();
        String bucket = ossConfig.getBucket();
        String key = AnnexGroupEnum.getAnnexGroupEnum(Integer.parseInt(annexGroup)).getName() + "/" + name;

        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        try {
            long expireTime = ossConfig.getUploadExpireTime();
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            URL url = client.generatePresignedUrl(bucket, key, expiration);
            Map<String, String> respMap = new LinkedHashMap<>(64);
            respMap.put("url", url.toString());
            JSONObject ja1 = JSONObject.fromObject(respMap);
            log.debug(ja1.toString());
            response(request, response, ja1.toString());
        } catch (Exception e) {
            log.error("error in getUrl", e);
        } finally {
            // 关闭client
            client.shutdown();
        }
    }

    /**
     * 新建订单时生成附件编号
     *
     * @return
     */
    @ApiOperation(value = "新建订单时生成附件编号", notes = "")
    @RequestMapping(value = {"/"}, method = RequestMethod.POST)
    public BizResult<AnnexListVO> createAnnexBatchNo() {
        BizResult<AnnexListVO> result = new BizResult<>();
        AnnexListVO annexListVO = new AnnexListVO();
        annexListVO.setAnnexBatchNo(UniqueIdGen.genUniqueId(AnnexConstant.ANNEX_BATCHNO_PREFIX));
        result.setData(annexListVO);
        result.setSuccess(true);
        result.setMessage("生成附件编号");
        return result;
    }

    /**
     * 上传,根据附件分组编号上传
     *
     * @param annexForm
     * @return
     */
    @ApiOperation(value = "上传附件", notes = "")
    @RequestMapping(value = {"/upload"}, method = RequestMethod.POST)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "annexForm", value = "附件详细实体annexForm", required = true, dataType = "AnnexForm")
    })
    public BizResult<AnnexListVO> upload(@AuthenticationPrincipal User logedUser, @RequestBody AnnexForm annexForm) {
        Optional<User> userOptional = Optional.ofNullable(logedUser);
        if (userOptional.isPresent()) {
            BizResult<AnnexListVO> result = new BizResult<>();
            if (StringUtils.isBlank(annexForm.getAnnexBatchNo())) {
                result.setMessage("附件批次为空，上传附件失败");
                result.setSuccess(false);
                return result;
            }
            AnnexListDO annexListDO = BeanCopierUtil.convert(annexForm, AnnexListDO.class);
            try {
                annexListDO.setStaffId(logedUser.getStaffId());
                result.setData(annexListService.addAnnex(annexListDO));
                result.setMessage("上传附件成功");
                result.setSuccess(true);
            } catch (Exception e) {
                log.error("error in upload", e);
                result.setMessage("上传附件失败");
                result.setSuccess(false);
            }
            return result;
        } else {
            return BizResult.create(ErrorCodeEnum.NOT_LOGIN.getErrCode(), ErrorCodeEnum.NOT_LOGIN.getErrMsg());
        }
    }


    /**
     * 删除附件
     *
     * @param annexId
     * @return
     */
    @ApiOperation(value = "删除附件", notes = "")
    @RequestMapping(value = {"/delete/{annexId}"}, method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "annexId", paramType = "path", value = "附件记录ID", required = true, dataType = "Long"),
    })
    public BizResult delete(@PathVariable Long annexId) {
        BizResult result = new BizResult();
        String endpoint = ossConfig.getEndpoint();
        String accessId = ossConfig.getAccessId();
        String accessKey = ossConfig.getAccessKey();
        String bucket = ossConfig.getBucket();
        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        try {
            AnnexListDO annexListDO = annexListService.getAnnex(annexId);
            if (annexListDO == null) {
                result.setMessage("删除附件失败,该附件已经被删除");
                result.setSuccess(false);
                return result;
            }
            annexListService.deleteAnnex(annexId);
            String key = AnnexGroupEnum.getAnnexGroupEnum(annexListDO.getAnnexGroup()).getName() + "/" + annexListDO.getAnnexUrl();
            client.deleteObject(bucket, key);
            result.setMessage("删除附件成功");
            result.setSuccess(true);
        } catch (Exception e) {
            log.error("error in delete", e);
            result.setMessage("删除附件失败");
            result.setSuccess(false);
        } finally {
            // 关闭client
            client.shutdown();
        }
        return result;
    }

    /**
     * 根据附件批次编号获取全部附件
     *
     * @param annexBatchNo
     * @return
     */
    @ApiOperation(value = "根据附件批次编号,附件类型获取全部附件", notes = "")
    @RequestMapping(value = {"/getAnnexList/{annexBatchNo}/{annexType}"}, method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "annexBatchNo", paramType = "path", value = "附件批次编号", required = true),
            @ApiImplicitParam(name = "annexType", paramType = "path", value = "业务类型", required = true, dataType = "Integer"),
    })
    public BizResult<List<AnnexListVO>> getAnnexList(@PathVariable String annexBatchNo,
                                                     @PathVariable Integer annexType) {
        BizResult<List<AnnexListVO>> bizResult = new BizResult<>();
        try {
            bizResult.setData(annexListService.getAnnexList(annexBatchNo, annexType));
            if(AnnexConstant.ANNEX_TYPE_CREDIT.equals(annexType)){
                bizResult.setMessage("获取征信附件列表成功");
            }else if(AnnexConstant.ANNEX_TYPE_ORDER.equals(annexType)){
                bizResult.setMessage("获取订单附件列表成功");
            }
            bizResult.setSuccess(true);
        } catch (Exception e) {
            log.error("error in getAnnexList", e);
            bizResult.setSuccess(false);
            bizResult.setMessage("获取附件列表信异常!");
        }
        return bizResult;
    }

}